package service

import (
	"bytes"
	"context"
	"encoding/json"
	"fx_swift_forex/api"
	"fx_swift_forex/internal/model"
	"fx_swift_forex/pkg/code"
	"fx_swift_forex/pkg/global"
	"fx_swift_forex/pkg/internalerrors"
	"fx_swift_forex/pkg/utils"
	"github.com/gogf/gf/v2/frame/g"
	"mime/multipart"
)

type IPaymentSrv interface {
	// 发起付款
	CreatePayments(ctx context.Context, req *api.CreatePaymentsReq) error

	// 获取付款人要求
	PayRequirements(ctx context.Context, req *api.PayRequirementsReq) (*api.PayRequirementsRes, error)

	// 取消、更新付款
	OperatorPayment(ctx context.Context, req *api.OperatorPaymentReq) error
}

type paymentSrv struct {
}

func NewPaymentSrv() IPaymentSrv {
	return &paymentSrv{}
}

// 发起付款
func (p *paymentSrv) CreatePayments(ctx context.Context, req *api.CreatePaymentsReq) error {
	var (
		createUrl = global.ViperObj.GetString("forex.baseUrl") + "/v2/payments/create"
		//validateUrl = global.ViperObj.GetString("forex.baseUrl") + "/v2/payments/validate"
		err  error
		body []byte
		obj  *api.CreatePaymentsRes
		//validateObj *api.ValidatePaymentRes
	)
	payload := &bytes.Buffer{}
	writer := multipart.NewWriter(payload)
	_ = writer.WriteField("currency", req.Currency)
	_ = writer.WriteField("beneficiary_id", req.BeneficiaryId)
	_ = writer.WriteField("amount", req.Amount)
	_ = writer.WriteField("reference", req.Reference)
	_ = writer.WriteField("reason", req.Reason)
	_ = writer.WriteField("unique_request_id", utils.GenerateCode32())
	//_ = writer.WriteField("payment_date", req.PaymentDate)
	//_ = writer.WriteField("payment_type", req.PaymentType)
	if len(req.PayerEntityType) > 0 {
		_ = writer.WriteField("payer_entity_type", req.PayerEntityType)
	}
	if len(req.PayerCountry) > 0 {
		_ = writer.WriteField("payer_country", req.PayerCountry)
	}
	if len(req.PayerCompanyName) > 0 {
		_ = writer.WriteField("payer_company_name", req.PayerCompanyName)
	}
	if len(req.PayerFirstName) > 0 {
		_ = writer.WriteField("payer_first_name", req.PayerFirstName)
	}
	if len(req.PayerLastName) > 0 {
		_ = writer.WriteField("payer_last_name", req.PayerLastName)
	}
	if len(req.PayerAddress) > 0 {
		_ = writer.WriteField("payer_address", req.PayerAddress)
	}
	if len(req.PayerCity) > 0 {
		_ = writer.WriteField("payer_city", req.PayerCity)
	}
	//body, err = PostRequestToCC(ctx, validateUrl, writer.FormDataContentType(), payload)
	//if err != nil {
	//	return internalerrors.New(code.ErrUnknown, err.Error())
	//}
	//if err = json.Unmarshal(body, &validateObj); err != nil {
	//	return internalerrors.New(code.ErrUnknown, err.Error())
	//}
	//if validateObj.ValidationResult == "success" {
	// 进行发起付款
	err = writer.Close()
	if err != nil {
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	body, err = PostRequestToCC(ctx, createUrl, writer.FormDataContentType(), payload)
	if err != nil {
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	if err = json.Unmarshal(body, &obj); err != nil {
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	// 写入库中
	if _, err = global.GFDB.Ctx(ctx).Model("forex_payment").Insert(&model.ForexPayment{
		PaymentId:                  obj.Id,
		Amount:                     obj.Amount,
		BeneficiaryId:              obj.BeneficiaryId,
		Currency:                   obj.Currency,
		Reason:                     obj.Reason,
		Reference:                  obj.Reference,
		Status:                     obj.Status,
		CreatorContactId:           obj.CreatorContactId,
		PaymentType:                obj.PaymentType,
		PaymentDate:                obj.PaymentDate,
		TransferredAt:              obj.TransferredAt,
		AuthorisationStepsRequired: obj.AuthorisationStepsRequired,
		LastUpdaterContactId:       obj.LastUpdaterContactId,
		ShortReference:             obj.ShortReference,
		ConversionId:               obj.ConversionId,
		FailureReason:              obj.FailureReason,
		PayerId:                    obj.PayerId,
		PurposeCode:                obj.PurposeCode,
		PaymentGroupId:             obj.PaymentGroupId,
		PayerDetailsSource:         obj.PayerDetailsSource,
		UltimateBeneficiaryName:    obj.UltimateBeneficiaryName,
		UniqueRequestId:            obj.UniqueRequestId,
		ChargeType:                 obj.ChargeType,
		FeeAmount:                  obj.FeeAmount,
		FeeCurrency:                obj.FeeCurrency,
		ReviewStatus:               obj.ReviewStatus,
		InvoiceNumber:              obj.InvoiceNumber,
		InvoiceDate:                obj.InvoiceDate,
	}); err != nil {
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	//}
	return err
}

// 获取付款人要求
func (p *paymentSrv) PayRequirements(ctx context.Context, req *api.PayRequirementsReq) (*api.PayRequirementsRes, error) {
	var (
		url       = global.ViperObj.GetString("forex.baseUrl") + "/v2/reference/payer_required_details"
		err       error
		body      []byte
		obj       *api.PayRequirementsRes
		mapParams = make(map[string]string, 0)
	)
	mapParams["payer_country"] = req.PayerCountry
	if len(req.PayerEntityType) > 0 {
		mapParams["payer_entity_type"] = req.PayerEntityType
	}
	if len(req.PaymentType) > 0 {
		mapParams["payment_type"] = req.PaymentType
	}
	if len(req.Currency) > 0 {
		mapParams["currency"] = req.Currency
	}
	body, err = GetRequestToCC(ctx, url, mapParams)
	if err != nil {
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	if err = json.Unmarshal(body, &obj); err != nil {
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	return obj, nil
}

// 取消、更新付款
func (p *paymentSrv) OperatorPayment(ctx context.Context, req *api.OperatorPaymentReq) error {
	var (
		cancelUrl = global.ViperObj.GetString("forex.baseUrl") + "/v2/payments/"
		updateUrl = global.ViperObj.GetString("forex.baseUrl") + "/v2/payments/"
		signStr   = "/delete"
		err       error
		body      []byte
		obj       *api.OperatorPaymentRes
	)
	payload := &bytes.Buffer{}
	writer := multipart.NewWriter(payload)
	if req.Method == "del" {
		body, err = PostRequestToCC(ctx, cancelUrl+req.PaymentId+signStr, writer.FormDataContentType(), payload)
		if err != nil {
			return internalerrors.New(code.ErrUnknown, err.Error())
		}
		if err = json.Unmarshal(body, &obj); err != nil {
			return internalerrors.New(code.ErrUnknown, err.Error())
		}
		if obj.Status == "deleted" {
			if _, err = global.GFDB.Ctx(ctx).Model("forex_payment").Data(g.Map{
				"status": obj.Status,
			}).Where("payment_id=?", req.PaymentId).Update(); err != nil {
				return internalerrors.New(code.ErrUnknown, err.Error())
			}
		}
	} else if req.Method == "update" {
		_ = writer.WriteField("currency", req.Currency)
		_ = writer.WriteField("beneficiary_id", req.BeneficiaryId)
		_ = writer.WriteField("amount", req.Amount)
		_ = writer.WriteField("reason", req.Reason)
		_ = writer.WriteField("unique_request_id", utils.GenerateCode32())
		_ = writer.WriteField("amount", req.PaymentDate)
		_ = writer.WriteField("payment_date", req.PaymentDate)
		_ = writer.WriteField("payment_type", req.PaymentType)
		if len(req.PayerEntityType) > 0 {
			_ = writer.WriteField("payer_entity_type", req.PayerEntityType)
		}
		if len(req.PayerCountry) > 0 {
			_ = writer.WriteField("payer_country", req.PayerCountry)
		}
		if len(req.PayerCompanyName) > 0 {
			_ = writer.WriteField("payer_company_name", req.PayerCompanyName)
		}
		if len(req.PayerFirstName) > 0 {
			_ = writer.WriteField("payer_first_name", req.PayerFirstName)
		}
		if len(req.PayerLastName) > 0 {
			_ = writer.WriteField("payer_last_name", req.PayerLastName)
		}
		if len(req.PayerAddress) > 0 {
			_ = writer.WriteField("payer_address", req.PayerAddress)
		}
		if len(req.PayerCity) > 0 {
			_ = writer.WriteField("payer_city", req.PayerCity)
		}
		err = writer.Close()
		if err != nil {
			return internalerrors.New(code.ErrUnknown, err.Error())
		}
		body, err = PostRequestToCC(ctx, updateUrl+req.PaymentId, writer.FormDataContentType(), payload)
		if err != nil {
			return internalerrors.New(code.ErrUnknown, err.Error())
		}
		if err = json.Unmarshal(body, &obj); err != nil {
			return internalerrors.New(code.ErrUnknown, err.Error())
		}
		if _, err = global.GFDB.Ctx(ctx).Model("forex_payment").Data(g.Map{
			"amount":                       obj.Amount,
			"beneficiary_id":               obj.BeneficiaryId,
			"currency":                     obj.Currency,
			"reference":                    obj.Reference,
			"reason":                       obj.Reason,
			"status":                       obj.Status,
			"creator_contact_id":           obj.CreatorContactId,
			"payment_type":                 obj.PaymentType,
			"payment_date":                 obj.PaymentDate,
			"transferred_at":               obj.TransferredAt,
			"authorisation_steps_required": obj.AuthorisationStepsRequired,
			"last_updater_contact_id":      obj.LastUpdaterContactId,
			"short_reference":              obj.ShortReference,
			"conversion_id":                obj.ConversionId,
			"failure_reason":               obj.FailureReason,
			"payer_id":                     obj.PayerId,
			"payer_details_source":         obj.PayerDetailsSource,
			"payment_group_id":             obj.PaymentGroupId,
			"unique_request_id":            obj.UniqueRequestId,
			"failure_returned_amount":      obj.FailureReturnedAmount,
			"ultimate_beneficiary_name":    obj.UltimateBeneficiaryName,
			"purpose_code":                 obj.PurposeCode,
			"charge_type":                  obj.ChargeType,
			"fee_amount":                   obj.FeeAmount,
			"fee_currency":                 obj.FeeCurrency,
			"review_status":                obj.ReviewStatus,
		}).Where("payment_id=?", req.PaymentId).Update(); err != nil {
			return internalerrors.New(code.ErrUnknown, err.Error())
		}
	}
	return err
}
